package com.z1.core.xml;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;

import org.apache.commons.beanutils.BeanUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.xml.sax.InputSource;

public class JavaBeanXmlUtil {

	public static <T> String bean2Xml(Class<T> clazz, T bean) {
		StringWriter sw = null;
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
            sw = new StringWriter();
            //该值默认为false,true则不会创建即头信息
            //即:<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
            jaxbMarshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
            jaxbMarshaller.marshal(bean, sw);
        }
        catch (JAXBException e) {
            e.printStackTrace();
        }
        return sw.toString();
	}
	
	@SuppressWarnings("unchecked")
	public static <T> T xml2Bean(Class<T> clazz, InputStream input) {
		if (null == input) { return null; }
		try {
			JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
			Unmarshaller jaxbMarshaller = jaxbContext.createUnmarshaller();
			return (T)jaxbMarshaller.unmarshal(input);
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static <T> T xml2Bean(Class<T> clazz, String xml) {
		InputStream input = null;
		try {
			input = new ByteArrayInputStream(xml.getBytes("UTF-8"));
			return xml2Bean(clazz, input);
		}
		catch (Throwable e) {
			e.printStackTrace();
		}
		finally {
			try {
				if (null != input) { input.close(); }
			}
			catch (Throwable e) { }
		}
		return null;
	}

	public static Object xml2Object(Class<?> clazz, String xml) {
		if (null != xml && !xml.equals("")) {
            Field[] fields = clazz.getDeclaredFields();
            Map<String, XmlBean> map = new HashMap<String, XmlBean>();
            for (Field field : fields) {
            	XmlElement element = field.getAnnotation(XmlElement.class);
            	if (null != element) {
            		String nodeName = element.name();
            		if (null != nodeName && !nodeName.trim().equals("")) {
            			map.put(nodeName, new XmlBean(nodeName, field.getName(), field.getClass()));
            		}
            	}
            }
            try {
                StringReader read = new StringReader(xml);
                InputSource source = new InputSource(read);
                //创建一个新的SAXBuilder
                SAXBuilder sb = new SAXBuilder();
                Document doc = sb.build(source);
                //取的根元素
                Element root = doc.getRootElement();
                Object t = clazz.newInstance();
                if (!map.isEmpty()) {
                    for (String nodeName : map.keySet()) {
                        Element child = root.getChild(nodeName);
                        if (null != child) {
                        	XmlBean xmlBean = map.get(nodeName);
                        	switch (xmlBean.getClazz().getName()) {
                        	case "java.lang.Integer" :
                        	case "java.lang.Long" :
                        	case "java.lang.Double" :	
                        		BeanUtils.setProperty(t, xmlBean.getFieldName(), child.getValue());
                        	default : 
                        		Object obj = xml2Bean(xmlBean.getClazz(), child.getValue().toString());
                        		BeanUtils.setProperty(t, xmlBean.getFieldName(), obj);
                        	}
                        }
                    }
                }
                return t;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
	}
	
}
